/*
Copyright 2008, 2009 Joonas Lehtolahti

This file is part of Shared Datatypes and Utilities.

Shared Datatypes and Utilities is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Shared Datatypes and Utilities is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Shared Datatypes and Utilities.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "helpers.h"
#include <string.h>

/**
 * SplitString
 *  Helper function to split a non0string* to LinkedList, taking escapes and quotes into account
 *
 * Parameters:
 *  snString  the string to be split
 *  szSep     separators
 *
 * Returns:
 *  A pointer to LinkedList structure that has the string tokens
 * 
 * Notes:
 *  The LinkedList contains non0string pointers that have their own memory allocated, so
 *  freeing the returned list should be done with LLdelete using n0sfree as the second parameter
 */
DLLEXPORT(LinkedList*) SplitString(non0string *snString, const char *szSep) {
	int escape = 0;
	unsigned char quote = 0;
	LinkedList *l = LLcreate();
	unsigned char *szString = snString->s;
	unsigned char *StringEnd = szString+snString->l;
	unsigned char *StringEndc = StringEnd+1;
	unsigned char c, *start, *walker;
	non0string *token;
	size_t length = 0;
	start = szString;
	do {
		if (escape == 0) {
			if (szString==StringEnd||(quote==0&&strchr(szSep, *szString))) {
				token = n0salloc(length);
				length=-1;
				walker = token->s;
				while (start != szString) {
					if (*start){
						*walker = *start;
						walker++;
					}
					start++;
				}
				start=szString+1;
				LLaddLast(l, token);
			} else {
				c = *szString;
				switch (c) {
					case '\\':
						if (szString!=StringEnd-1) {
							escape = 1;
							*szString = '\0';
							length--;
						}
						break;
					case '\"':
					case '\'':
						if (quote==0) {
							quote = c;
							*szString = '\0';
							length--;
						}
						else if (quote==c) {
							quote = 0;
							*szString = '\0';
							length--;
						}
					/* no more cases */
				}
			}
		} else {
			escape = 0;
		}
		szString++;
		length++;
	} while (szString<StringEndc);
	return l;
}

/**
 * EvalEscapes
 *  Parses string and does escape sequences
 *
 * Parameters:
 *  retstr    pointer to allocated string space, must have enough space!
 *  original  the string to be evaluated
 *
 * Returns:
 *  Nothing
 */
DLLEXPORT(void) EvalEscapes(char *retstr, char *original) {
	char *wret = retstr, *wori = original;
	int escape = 0;
	while (*wori) {
		if (escape == 0) {
			if (*wori == '\\')
				escape = 1;
			else {
				*wret = *wori;
				wret++;
			}
		}
		else {
			if (*wori == 'x') {
				*wret = (char)hex2int(++wori,16);
				wori++;
			} else if (*wori == 'n') {
				*wret = '\n';
			} else if (*wori == '0') {
				*wret = '\0';
			} else if (*wori == 't') {
				*wret = '\t';
			} else if (*wori == 'a') {
				*wret = '\a';
			} else if (*wori == 'f') {
				*wret = '\f';
			} else if (*wori == 'b') {
				*wret = '\b';
			} else {
				*wret = *wori;
			}
			wret++;
			escape = 0;
		}
		wori++;
	}
	*wret = 0;
}

DLLEXPORT(unsigned int) hex2int(char *cc, int multiplier) {
	unsigned int r = 0;
	int c;
	while (multiplier) {
		c = *cc;
		if (c == 0) return 0;
		if (c >= '0' && c <= '9')
			r += multiplier*(c-'0');
		else {
			if (c >= 'a') c-=32;
			if (c >= 'A' && c <= 'F')
				r += multiplier*(c-'A'+10);
			else
				return 0;
		}
		multiplier /= 16;
		cc++;
	}
	return r;
}

DLLEXPORT(non0string*) shorten_to(non0string *original, size_t max_length) {
	non0string *new_one = n0salloc(max_length);
	unsigned char *ow = original->s, *nw = new_one->s;
	size_t new_length = 0;
	while (*ow && new_length < max_length) {
		if (*ow == '\n' || *ow == '\r') {
			*nw = ' ';
		}
		else *nw = *ow;
		nw++;
		ow++;
		new_length++;
	}
	*nw = '\0';
	if (new_length == max_length) {
		/* max! convert last three characters to ellipsis */
		*(--nw) = '.';
		*(--nw) = '.';
		*(--nw) = '.';
	}
	new_one->l = new_length;
	return new_one;
}


DLLEXPORT(void) DumpObject(void *x, size_t l) {
	unsigned int i;
	unsigned char *w = (unsigned char*)x;
	fprintf(stderr, "Object at address %p:\n", x);
	for(i=0;i<l;i++) {
		fprintf(stderr, "%02X ",w[i]);
	}
	fprintf(stderr, "\n\n");
}
